/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab-modules.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_Versatile_ModelTechnique_h__
#define __dylab_Versatile_ModelTechnique_h__

//===========================================================================================
#include <dylab/utils/containers/ListContainer.h>
#include <dylab/simobject/ComModelStructure.h>
#include <dylab/simobject/ComModelTechnique.h>
#include <dylab/simobject/masspoints/MassPoint.h>
#include <dylab/simobject/tetravol/Tetrahedron.h>

//===========================================================================================
namespace dylab {

    /**
     */
    class Versatile_ModelTechnique 
        : public ComModelTechnique
    {
    private:
        typedef MassPoint   MassPoint;
        typedef Edge        Edge;
        typedef Triangle    Triangle;
        typedef Tetrahedron Tetrahedron;

    public:
        static const String COMPONENT_NAME;

    private:
        //-----------------------------------------------------------------------------
        /// distance constraint generates forces between each pair of tetrahedron points
        class DistanceConstraint
        {
        private:
            ///
            Edge * mEdge;
            /// original distance between the points of the edge
            real_t mOriginalDistance;
            /// _stiffness factor (usually between 1 and 100)
            real_t mStiffness;
            /// _damping coefficient (usually between 0.0001 and 0.001)
            real_t mDamping;
            ///
            bool   mPlasticEnabled;
            /// minimum total energy of this line segment to start absorb the plastic energy
            real_t mPlasticYieldEnergy;
            /// 
            real_t mPlasticMaxEnergy;
            ///
            real_t mPlasticCreep;
            /// current plastic energy of the this line segment (defined by its distance)
            real_t mPlasticCurrEnergy;

        public:

            DistanceConstraint(Edge * _edge);            
            void performComputation();
            
            void setStiffness(real_t _stiffness) 
                    { mStiffness = _stiffness; }
            real_t getStiffness() const 
                    { return mStiffness; }        
            
            void setDamping(real_t _damping) 
                    { mDamping = _damping; }
            real_t getDamping() const 
                    { return mDamping; }        
            
            void setPlasticEnabled(bool _enabled)
                    { mPlasticEnabled = _enabled; }
            bool isPlasticEnabled() const 
                    { return mPlasticEnabled; }
            
            void setPlasticYieldEnergy(real_t plasticYieldEnergy)
                    { mPlasticYieldEnergy = plasticYieldEnergy; }
            real_t getPlasticYieldEnergy() const
                    { return mPlasticYieldEnergy; }
            
            void setPlasticMaxEnergy(real_t plasticMaxEnergy)
                    { mPlasticMaxEnergy = plasticMaxEnergy; }
            real_t getPlasticMaxEnergy() const
                    { return mPlasticMaxEnergy; }

            void setPlasticCreep(real_t plasticCreep)
                    { mPlasticCreep = plasticCreep; }
            real_t getPlasticCreep() const
                    { return mPlasticCreep; }

            real_t getPlasticCurrEnergy() const
                    { return mPlasticCurrEnergy; }
        };        
        //-----------------------------------------------------------------------------
        /// area constraint generates forces between each triplet of tetrahedron triangles
        class AreaConstraint
        {
        private:  
            Triangle * mTriangle;
            real_t mOriginalArea; 
            real_t mStiffness; 

        public:
            AreaConstraint(Triangle * _triangle);
            void performComputation();
            void setStiffness(real_t _stiffness) 
                    { mStiffness = _stiffness; }
        };
        //-----------------------------------------------------------------------------
        /// volume constraint generates forces between all tetrahedron mass points
        class VolumeConstraint
        {
        private:
            Tetrahedron * mTetrahedron;
            real_t mOriginalVolume;
            real_t mStiffness;

        public:
            VolumeConstraint(Tetrahedron * _tetrahedron);
            void performComputation();
            void setStiffness(real_t _stiffness) 
                    { mStiffness = _stiffness; }
        };
        //-----------------------------------------------------------------------------
    private:
        typedef HashObjContainer<Edge::id_t, DistanceConstraint> DistanceConstraints;
        typedef HashObjContainer<Triangle::id_t, AreaConstraint> AreaConstraints;
        typedef HashObjContainer<Tetrahedron::id_t, VolumeConstraint> VolumeConstraints;

        typedef std::pair<MassPoint*, Vector3> LocalForce;
        typedef ListContainer<LocalForce> LocalForces;

    private:
        
        /// parent simulation object
        SimObject * mParentSimObject;
        
        /// object does not own this pointer
        ComModelStructure::Instance * mModel;
        
        /// distance constraints activation flag (set by default)
        bool mDistanceConstraintsEnabled;

        /// the distance constraints of the mesh edges that generates equilibrium forces
        DistanceConstraints mDistanceConstraints;
        
        /// area constraints activation flag (set by default)
        bool mAreaConstraintsEnabled;

        /// the area constraints of the mesh tetrahedrons that generates equilibrium forces
        AreaConstraints mAreaConstraints;

        /// volume constraints activation flag (set by default)
        bool mVolumeConstraintsEnabled;

        /// the volume constraints of the mesh tetrahedrons that generates equilibrium forces
        VolumeConstraints mVolumeConstraints;

        /// consists of pairs: mass point (MassPoint*) x its local force (Vector3)
        LocalForces mLocalForces;

    public:        
        
        Versatile_ModelTechnique();        
        virtual ~Versatile_ModelTechnique();
        
        virtual String getDescription() const;                
        virtual void initialize(SimObject * _parentSimObject);     
		virtual void loadFromPropertyTree(const PropertyTree & _pt);
        virtual SimObject * getParentSimObject();
        virtual const SimObject * getParentSimObject() const;
        
        virtual void performComputation();        
        
        void setDistanceStiffness(real_t _stiffness);        
        void setDistanceDamping(real_t _damping);        
        void setPlasticEnabled(bool _enabled);        
        void setPlasticYieldEnergy(real_t _plasticYieldEnergy);        
        void setPlasticMaxEnergy(real_t _plasticMaxEnergy);        
        void setPlasticCreep(real_t _plasticCreep);        
        void setAreaStiffness(real_t _stiffness);        
        void setVolumeStiffness(real_t _stiffness);        
        
        void setDistanceConstraintsEnabled(bool _enabled) 
                { mDistanceConstraintsEnabled = _enabled; }        
        bool isDistanceConstraintsEnabled() const 
                { return mDistanceConstraintsEnabled; }
        void setVolumeConstraintsEnabled(bool _enabled) 
                { mVolumeConstraintsEnabled = _enabled; }        
        bool isVolumeConstraintsEnabled() const 
                { return mVolumeConstraintsEnabled; }        
        void setAreaConstraintsEnabled(bool _enabled) 
                { mAreaConstraintsEnabled = _enabled; }        
        bool isAreaConstraintsEnabled() const 
                { return mAreaConstraintsEnabled; }
    };

}

//===========================================================================================
#endif // __dylab_Versatile_ModelTechnique_h__